#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
下载True实的Side-Channel AttackTraceData集
SupportAESAndSM4Algorithm
"""

import os
import sys
import requests
import zipfile
import h5py
import numpy as np
from pathlib import Path
from tqdm import tqdm
import argparse


class TraceDatasetDownloader:
    """TraceData集下载器"""
    
    def __init__(self, output_dir: str = "datasets"):
        self.output_dir = Path(output_dir)
        self.output_dir.mkdir(exist_ok=True)
        
    def download_file(self, url: str, output_path: Path, desc: str = "Downloading"):
        """下载File并Display进度条"""
        if output_path.exists():
            print(f"File已存In: {output_path}")
            return True
            
        try:
            print(f"正In下载: {url}")
            response = requests.get(url, stream=True)
            response.raise_for_status()
            
            total_size = int(response.headers.get('content-length', 0))
            
            with open(output_path, 'wb') as f:
                with tqdm(total=total_size, unit='B', unit_scale=True, desc=desc) as pbar:
                    for chunk in response.iter_content(chunk_size=8192):
                        if chunk:
                            f.write(chunk)
                            pbar.update(len(chunk))
            
            print(f"下载Completed: {output_path}")
            return True
            
        except Exception as e:
            print(f"下载Failed: {e}")
            if output_path.exists():
                output_path.unlink()
            return False
    
    def extract_zip(self, zip_path: Path, extract_dir: Path):
        """解压ZIPFile"""
        try:
            print(f"正In解压: {zip_path}")
            with zipfile.ZipFile(zip_path, 'r') as zip_ref:
                zip_ref.extractall(extract_dir)
            print(f"解压Completed: {extract_dir}")
            return True
        except Exception as e:
            print(f"解压Failed: {e}")
            return False
    
    def download_dpa_contest_v4(self):
        """
        下载DPA Contest V4Data集
        IncludeAES-256的True实PowerTrace
        """
        print("\n=== 下载DPA Contest V4Data集 ===")
        print("Algorithm: AES-256")
        print("设备: SASEBO-GII FPGA")
        print("Trace数: 约80,000条")
        print("Sampling点: 3,500点/Trace")
        
        dataset_dir = self.output_dir / "dpa_contest_v4"
        dataset_dir.mkdir(exist_ok=True)
        
        # DPA Contest V4的DataFile
        files = {
            "attack_traces": "http://www.dpacontest.org/v4/rsm_8bit_attack.zip",
            "profiling_traces": "http://www.dpacontest.org/v4/rsm_8bit_profiling.zip"
        }
        
        downloaded_files = []
        for name, url in files.items():
            output_file = dataset_dir / f"{name}.zip"
            if self.download_file(url, output_file, desc=f"Downloading {name}"):
                # 解压
                extract_dir = dataset_dir / name
                extract_dir.mkdir(exist_ok=True)
                self.extract_zip(output_file, extract_dir)
                downloaded_files.append(extract_dir)
        
        if downloaded_files:
            # ConvertForNPZFormat
            npz_file = self.convert_dpa_v4_to_npz(dataset_dir)
            if npz_file:
                print(f"\n[OK] DPA Contest V4Data集已准备就绪: {npz_file}")
                return npz_file
        
        return None
    
    def download_ascad(self):
        """
        下载ASCADData集
        IncludeAES-128的True实PowerTrace
        """
        print("\n=== 下载ASCADData集 ===")
        print("Algorithm: AES-128")
        print("设备: ATMega8515 (8-bit AVR)")
        print("Trace数: 60,000条 (训练) + 10,000条 (Test)")
        print("Sampling点: 700点/Trace")
        
        dataset_dir = self.output_dir / "ascad"
        dataset_dir.mkdir(exist_ok=True)
        
        # ASCADData集URL (Use固定KeyVersion)
        url = "https://www.data.gouv.fr/s/resources/ascad/20180530-163000/ASCAD_data.zip"
        
        output_file = dataset_dir / "ASCAD_data.zip"
        
        # Note：ASCADData集很大（约4GB），下载可能Require较长时间
        print("Warning: ASCADData集约4GB，下载可能Require较长时间")
        response = input("YesNoContinue下载? (y/n): ")
        if response.lower() != 'y':
            print("SkipASCAD下载")
            return None
        
        if self.download_file(url, output_file, desc="Downloading ASCAD"):
            extract_dir = dataset_dir / "extracted"
            extract_dir.mkdir(exist_ok=True)
            self.extract_zip(output_file, extract_dir)
            
            # ConvertForNPZFormat
            npz_file = self.convert_ascad_to_npz(extract_dir)
            if npz_file:
                print(f"\n[OK] ASCADData集已准备就绪: {npz_file}")
                return npz_file
        
        return None
    
    def download_chipwhisperer_example(self):
        """
        下载ChipWhispererExampleData
        IncludeAES-128的True实PowerTrace
        """
        print("\n=== 下载ChipWhispererExampleData ===")
        print("Algorithm: AES-128")
        print("设备: STM32F3 (软件AES)")
        print("Trace数: 2,500条")
        print("Sampling点: 3,000点/Trace")
        
        dataset_dir = self.output_dir / "chipwhisperer"
        dataset_dir.mkdir(exist_ok=True)
        
        # ChipWhisperer GitHub上的ExampleData
        url = "https://github.com/newaetech/chipwhisperer-jupyter/raw/master/courses/sca101/SOLN_Lab%202_1B%20-%20Power%20Analysis%20for%20Password%20Bypass.zip"
        
        output_file = dataset_dir / "cw_example.zip"
        
        if self.download_file(url, output_file, desc="Downloading ChipWhisperer Example"):
            extract_dir = dataset_dir / "extracted"
            extract_dir.mkdir(exist_ok=True)
            self.extract_zip(output_file, extract_dir)
            
            print(f"\n[OK] ChipWhispererExampleData已下载: {extract_dir}")
            print("Note: Require手动UseChipWhispererTool导出ForNPZFormat")
            return extract_dir
        
        return None
    
    def create_rsa_synthetic_dataset(self):
        """
        CreateRSA合成Data集（用于Test）
        模拟RSA-2048的CRT实现Power泄漏
        """
        print("\n=== CreateRSA合成Data集 ===")
        print("Algorithm: RSA-2048 (CRT实现)")
        print("Warning: 这Yes合成Data用于代码Test")
        
        dataset_dir = self.output_dir / "rsa_synthetic"
        dataset_dir.mkdir(exist_ok=True)
        
        # RSAParameters
        num_traces = 2000  # RSAAttack通常Require较少Trace
        trace_length = 3000  # RSA操作较长
        key_bits = 2048
        
        print(f"Generate {num_traces} 条RSATrace...")
        
        # Generate随机私钥Parameters（简化版）
        # InTrue实Attack中，我们试图恢复私钥dOrCRTParametersdp, dq
        d = np.random.randint(1, 2**16, dtype=np.uint16)  # 简化的私钥指数
        
        # Generate随机消息
        messages = np.random.randint(0, 2**16, (num_traces,), dtype=np.uint16)
        
        # Generate合成Trace
        traces = np.random.randn(num_traces, trace_length).astype(np.float32) * 0.1
        
        # AddRSA模幂运算的Power泄漏
        for i in range(num_traces):
            # 模拟平方-乘Algorithm的Power泄漏
            msg = messages[i]
            exp = d
            
            # 模拟Eachbit的Process
            for bit_pos in range(16):
                bit = (exp >> bit_pos) & 1
                position = 200 + bit_pos * 150
                
                # 平方操作（总YesExecute）
                traces[i, position:position+50] += 0.8
                
                # 乘法操作（只Inbit=1时Execute）- 这Yes关键泄漏
                if bit == 1:
                    traces[i, position+60:position+110] += 1.2
                    # Add与消息相关的泄漏
                    hw = bin(msg).count('1')
                    traces[i, position+60:position+110] += hw * 0.1
        
        # SaveForNPZ
        npz_file = dataset_dir / "rsa_synthetic_traces.npz"
        np.savez(
            npz_file,
            power_traces=traces,
            traces=traces,
            cpu_traces=traces,
            messages=messages,
            plaintexts=messages.reshape(-1, 1),  # 兼容性
            keys=np.tile(d, (num_traces, 1)),
            private_exponent=d,
            algorithm='rsa'
        )
        
        print(f"\n[OK] RSA合成Data集已Create: {npz_file}")
        print("Data特征:")
        print(f"  - Trace数量: {num_traces}")
        print(f"  - Trace长度: {trace_length}")
        print(f"  - Key位数: {key_bits}")
        print(f"  - 私钥指数(简化): {d}")
        print(f"  - Include平方-乘Algorithm泄漏，应该可以SuccessAttack")
        
        return npz_file
    
    def create_ecc_synthetic_dataset(self):
        """
        CreateECC合成Data集（用于Test）
        模拟ECDSA签名中的Scalar乘法Power泄漏
        """
        print("\n=== CreateECC合成Data集 ===")
        print("Algorithm: ECDSA P-256")
        print("Warning: 这Yes合成Data用于代码Test")
        
        dataset_dir = self.output_dir / "ecc_synthetic"
        dataset_dir.mkdir(exist_ok=True)
        
        # ECCParameters
        num_traces = 3000
        trace_length = 2500
        key_bits = 256
        
        print(f"Generate {num_traces} 条ECCTrace...")
        
        # Generate随机私钥（Scalar）
        private_key = np.random.randint(1, 2**32, dtype=np.uint32)
        
        # Generate随机消息哈希
        message_hashes = np.random.randint(0, 2**32, (num_traces,), dtype=np.uint32)
        
        # Generate合成Trace
        traces = np.random.randn(num_traces, trace_length).astype(np.float32) * 0.1
        
        # AddScalar乘法的Power泄漏（double-and-addAlgorithm）
        for i in range(num_traces):
            k = private_key  # Scalar（私钥）
            
            # 模拟Eachbit的Process
            for bit_pos in range(32):
                bit = (k >> bit_pos) & 1
                position = 100 + bit_pos * 70
                
                # Point doubling（总YesExecute）
                traces[i, position:position+30] += 0.7
                
                # Point addition（只Inbit=1时Execute）- 关键泄漏
                if bit == 1:
                    traces[i, position+35:position+65] += 1.0
                    # AddHamming weight泄漏
                    hw = bin(message_hashes[i]).count('1')
                    traces[i, position+35:position+65] += hw * 0.05
        
        # SaveForNPZ
        npz_file = dataset_dir / "ecc_synthetic_traces.npz"
        np.savez(
            npz_file,
            power_traces=traces,
            traces=traces,
            cpu_traces=traces,
            message_hashes=message_hashes,
            plaintexts=message_hashes.reshape(-1, 1),  # 兼容性
            keys=np.tile(private_key, (num_traces, 1)),
            private_key=private_key,
            algorithm='ecc'
        )
        
        print(f"\n[OK] ECC合成Data集已Create: {npz_file}")
        print("Data特征:")
        print(f"  - Trace数量: {num_traces}")
        print(f"  - Trace长度: {trace_length}")
        print(f"  - 曲线: P-256")
        print(f"  - 私钥(简化): {private_key}")
        print(f"  - Includedouble-and-add泄漏，应该可以SuccessAttack")
        
        return npz_file
    
    def create_sm2_synthetic_dataset(self):
        """
        CreateSM2合成Data集（用于Test）
        模拟SM2签名中的Scalar乘法Power泄漏
        """
        print("\n=== CreateSM2合成Data集 ===")
        print("Algorithm: SM2 (国密Elliptic Curve)")
        print("Warning: 这Yes合成Data用于代码Test")
        
        dataset_dir = self.output_dir / "sm2_synthetic"
        dataset_dir.mkdir(exist_ok=True)
        
        # SM2Parameters（与ECCClass似但Use国密曲线）
        num_traces = 3000
        trace_length = 2500
        key_bits = 256
        
        print(f"Generate {num_traces} 条SM2Trace...")
        
        # Generate随机私钥
        private_key = np.random.randint(1, 2**32, dtype=np.uint32)
        
        # Generate随机消息哈希（UseSM3）
        message_hashes = np.random.randint(0, 2**32, (num_traces,), dtype=np.uint32)
        
        # Generate合成Trace
        traces = np.random.randn(num_traces, trace_length).astype(np.float32) * 0.1
        
        # AddScalar乘法的Power泄漏
        for i in range(num_traces):
            k = private_key
            
            for bit_pos in range(32):
                bit = (k >> bit_pos) & 1
                position = 100 + bit_pos * 70
                
                # Point doubling
                traces[i, position:position+30] += 0.75
                
                # Point addition（bit=1时）
                if bit == 1:
                    traces[i, position+35:position+65] += 1.05
                    hw = bin(message_hashes[i]).count('1')
                    traces[i, position+35:position+65] += hw * 0.06
        
        # SaveForNPZ
        npz_file = dataset_dir / "sm2_synthetic_traces.npz"
        np.savez(
            npz_file,
            power_traces=traces,
            traces=traces,
            cpu_traces=traces,
            message_hashes=message_hashes,
            plaintexts=message_hashes.reshape(-1, 1),
            keys=np.tile(private_key, (num_traces, 1)),
            private_key=private_key,
            algorithm='sm2'
        )
        
        print(f"\n[OK] SM2合成Data集已Create: {npz_file}")
        print("Data特征:")
        print(f"  - Trace数量: {num_traces}")
        print(f"  - Trace长度: {trace_length}")
        print(f"  - 曲线: SM2 (国密)")
        print(f"  - 私钥(简化): {private_key}")
        print(f"  - IncludeScalar乘法泄漏，应该可以SuccessAttack")
        
        return npz_file
    
    def create_dilithium_synthetic_dataset(self):
        """
        CreateDilithium合成Data集（用于Test）
        模拟DilithiumPost-Quantum签名Algorithm的Power泄漏
        """
        print("\n=== CreateDilithium合成Data集 ===")
        print("Algorithm: Dilithium (Post-Quantum签名Algorithm)")
        print("Warning: 这Yes合成Data用于代码Test")
        
        dataset_dir = self.output_dir / "dilithium_synthetic"
        dataset_dir.mkdir(exist_ok=True)
        
        # DilithiumParameters
        num_traces = 4000
        trace_length = 3500  # Dilithium操作较复杂，Trace较长
        n = 256  # 多项式维度
        
        print(f"Generate {num_traces} 条DilithiumTrace...")
        
        # Generate随机私钥系数（简化版）
        # True实的DilithiumUse多项式Vector
        private_key = np.random.randint(-2, 3, n, dtype=np.int8)  # 小系数
        
        # Generate随机消息哈希
        message_hashes = np.random.randint(0, 2**32, (num_traces,), dtype=np.uint32)
        
        # Generate合成Trace
        traces = np.random.randn(num_traces, trace_length).astype(np.float32) * 0.1
        
        # AddDilithium关键操作的Power泄漏
        for i in range(num_traces):
            # 1. NTT变换泄漏（Number Theoretic Transform）
            ntt_start = 100
            for j in range(0, n, 8):  # 分批Process
                # NTT蝶形运算的Power
                position = ntt_start + j * 10
                coeff_sum = np.sum(np.abs(private_key[j:j+8]))
                traces[i, position:position+8] += coeff_sum * 0.08
            
            # 2. 多项式乘法泄漏
            polymul_start = 1200
            for j in range(0, n, 16):
                position = polymul_start + j * 5
                # 模拟乘法操作的Power
                coeff_product = np.abs(private_key[j]) * (message_hashes[i] & 0xFF)
                traces[i, position:position+10] += (coeff_product % 256) * 0.06
            
            # 3. 拒绝Sampling泄漏（Rejection Sampling）
            rejection_start = 2500
            # 拒绝Sampling的迭代次数泄漏
            num_rejections = np.random.poisson(2)  # 平均2次拒绝
            for rej in range(num_rejections):
                position = rejection_start + rej * 150
                traces[i, position:position+100] += 0.5
            
            # 4. Hamming weight泄漏
            hw_start = 3000
            hw = bin(message_hashes[i]).count('1')
            traces[i, hw_start:hw_start+200] += hw * 0.04
        
        # SaveForNPZ
        npz_file = dataset_dir / "dilithium_synthetic_traces.npz"
        np.savez(
            npz_file,
            power_traces=traces,
            traces=traces,
            cpu_traces=traces,
            message_hashes=message_hashes,
            plaintexts=message_hashes.reshape(-1, 1),  # 兼容性
            keys=np.tile(private_key[:16], (num_traces, 1)),  # 取前16个系数
            private_key_coeffs=private_key,
            polynomial_dimension=n,
            algorithm='dilithium'
        )
        
        print(f"\n[OK] Dilithium合成Data集已Create: {npz_file}")
        print("Data特征:")
        print(f"  - Trace数量: {num_traces}")
        print(f"  - Trace长度: {trace_length}")
        print(f"  - 多项式维度: {n}")
        print(f"  - 私钥系数范围: [-2, 2]")
        print(f"  - IncludeNTT、多项式乘法、拒绝Sampling泄漏")
        print(f"  - 应该可以识别关键操作模式")
        
        return npz_file
    
    def create_sm4_synthetic_dataset(self):
        """
        CreateSM4合成Data集（用于Test）
        Note：这Yes合成Data，NotYesTrue实硬件采集的Trace
        """
        print("\n=== CreateSM4合成Data集 ===")
        print("Warning: SM4的True实公开Data集非常稀少")
        print("这里Create合成Data用于代码Test")
        
        dataset_dir = self.output_dir / "sm4_synthetic"
        dataset_dir.mkdir(exist_ok=True)
        
        # Create合成Data
        num_traces = 5000
        trace_length = 2000
        
        print(f"Generate {num_traces} 条Trace...")
        
        # Generate随机Key
        key = np.random.randint(0, 256, 16, dtype=np.uint8)
        
        # GeneratePlaintext
        plaintexts = np.random.randint(0, 256, (num_traces, 16), dtype=np.uint8)
        
        # Generate合成Trace（AddKey相关的模式）
        traces = np.random.randn(num_traces, trace_length).astype(np.float32)
        
        # In关键时间点AddKey泄漏
        for i in range(num_traces):
            for byte_idx in range(16):
                # 模拟S-boxOutput的泄漏
                intermediate = plaintexts[i, byte_idx] ^ key[byte_idx]
                hw = bin(intermediate).count('1')
                
                # InTrace的特定位置AddHamming weight相关的信号
                leak_position = 200 + byte_idx * 100
                traces[i, leak_position:leak_position+50] += hw * 0.5
        
        # SaveForNPZ（UseMultiple键名以兼容Not同的Load器）
        npz_file = dataset_dir / "sm4_synthetic_traces.npz"
        np.savez(
            npz_file,
            power_traces=traces,
            traces=traces,  # 兼容性别名
            cpu_traces=traces,  # 兼容性别名
            plaintexts=plaintexts,
            keys=np.tile(key, (num_traces, 1)),
            algorithm='sm4'
        )
        
        print(f"\n[OK] SM4合成Data集已Create: {npz_file}")
        print("Data特征:")
        print(f"  - Trace数量: {num_traces}")
        print(f"  - Trace长度: {trace_length}")
        print(f"  - Key: {key.tobytes().hex()}")
        print(f"  - Include人工泄漏，应该可以SuccessAttack")
        
        return npz_file
    
    def convert_dpa_v4_to_npz(self, dataset_dir: Path):
        """将DPA Contest V4DataConvertForNPZFormat"""
        print("\n正InConvertDPA Contest V4DataForNPZFormat...")
        
        # Findattack_tracesDirectory中的DataFile
        attack_dir = dataset_dir / "attack_traces"
        if not attack_dir.exists():
            print("未找Toattack_tracesDirectory")
            return None
        
        # DPA Contest V4UseMATFileFormat
        # 这里Provide一个Convert模板
        print("Note: DPA Contest V4Use.matFormat")
        print("Require安装scipy: pip install scipy")
        
        try:
            from scipy.io import loadmat
            
            # Find.matFile
            mat_files = list(attack_dir.glob("*.mat"))
            if not mat_files:
                print("未找To.matFile")
                return None
            
            print(f"找To {len(mat_files)} 个.matFile")
            
            # LoadFirst个File作ForExample
            mat_data = loadmat(mat_files[0])
            
            # ExtractData（According to实际File结构调整）
            traces = mat_data.get('traces', mat_data.get('L', None))
            plaintexts = mat_data.get('plaintext', mat_data.get('P', None))
            keys = mat_data.get('key', mat_data.get('K', None))
            
            if traces is not None:
                # SaveForNPZ（UseMultiple键名以兼容Not同的Load器）
                npz_file = dataset_dir / "dpa_v4_traces.npz"
                np.savez(
                    npz_file,
                    power_traces=traces,
                    traces=traces,  # 兼容性别名
                    cpu_traces=traces,  # 兼容性别名
                    plaintexts=plaintexts,
                    keys=keys,
                    algorithm='aes'
                )
                
                print(f"ConvertSuccess: {npz_file}")
                return npz_file
            
        except ImportError:
            print("Require安装scipy: pip install scipy")
        except Exception as e:
            print(f"ConvertFailed: {e}")
        
        return None
    
    def convert_ascad_to_npz(self, extract_dir: Path):
        """将ASCADDataConvertForNPZFormat"""
        print("\n正InConvertASCADDataForNPZFormat...")
        
        # ASCADUseHDF5Format
        h5_files = list(extract_dir.glob("*.h5"))
        if not h5_files:
            print("未找To.h5File")
            return None
        
        print(f"找To {len(h5_files)} 个.h5File")
        
        try:
            # LoadASCADData
            with h5py.File(h5_files[0], 'r') as f:
                # ASCADData结构
                traces = np.array(f['Profiling_traces/traces'])
                plaintexts = np.array(f['Profiling_traces/metadata']['plaintext'])
                keys = np.array(f['Profiling_traces/metadata']['key'])
                
                # 只Use前5000条Trace（加快Test）
                traces = traces[:5000]
                plaintexts = plaintexts[:5000]
                keys = keys[:5000]
                
                # SaveForNPZ（UseMultiple键名以兼容Not同的Load器）
                npz_file = extract_dir.parent / "ascad_traces.npz"
                np.savez(
                    npz_file,
                    power_traces=traces.astype(np.float32),
                    traces=traces.astype(np.float32),  # 兼容性别名
                    cpu_traces=traces.astype(np.float32),  # 兼容性别名
                    plaintexts=plaintexts,
                    keys=keys,
                    algorithm='aes'
                )
                
                print(f"ConvertSuccess: {npz_file}")
                print(f"Trace数量: {len(traces)}")
                print(f"Trace长度: {traces.shape[1]}")
                return npz_file
                
        except Exception as e:
            print(f"ConvertFailed: {e}")
            print("Require安装h5py: pip install h5py")
        
        return None


def main():
    parser = argparse.ArgumentParser(description="下载True实的Side-Channel AttackTraceData集")
    parser.add_argument('--output', '-o', default='datasets', help='Output directory')
    parser.add_argument('--dataset', '-d', 
                       choices=['all', 'all_synthetic', 'dpa_v4', 'ascad', 'chipwhisperer', 
                               'sm4_synthetic', 'rsa_synthetic', 'ecc_synthetic', 'sm2_synthetic',
                               'dilithium_synthetic'],
                       default='all',
                       help='选择要下载的Data集')
    
    args = parser.parse_args()
    
    downloader = TraceDatasetDownloader(args.output)
    
    print("=" * 70)
    print("  True实Side-Channel AttackTraceData集下载Tool")
    print("=" * 70)
    
    downloaded = []
    
    # True实Data集
    if args.dataset in ['all', 'dpa_v4']:
        result = downloader.download_dpa_contest_v4()
        if result:
            downloaded.append(('DPA Contest V4 (AES-256)', result))
    
    if args.dataset in ['all', 'ascad']:
        result = downloader.download_ascad()
        if result:
            downloaded.append(('ASCAD (AES-128)', result))
    
    if args.dataset in ['all', 'chipwhisperer']:
        result = downloader.download_chipwhisperer_example()
        if result:
            downloaded.append(('ChipWhisperer Example', result))
    
    # 合成Data集
    if args.dataset in ['all', 'all_synthetic', 'sm4_synthetic']:
        result = downloader.create_sm4_synthetic_dataset()
        if result:
            downloaded.append(('SM4 Synthetic', result))
    
    if args.dataset in ['all', 'all_synthetic', 'rsa_synthetic']:
        result = downloader.create_rsa_synthetic_dataset()
        if result:
            downloaded.append(('RSA Synthetic', result))
    
    if args.dataset in ['all', 'all_synthetic', 'ecc_synthetic']:
        result = downloader.create_ecc_synthetic_dataset()
        if result:
            downloaded.append(('ECC Synthetic', result))
    
    if args.dataset in ['all', 'all_synthetic', 'sm2_synthetic']:
        result = downloader.create_sm2_synthetic_dataset()
        if result:
            downloaded.append(('SM2 Synthetic', result))
    
    if args.dataset in ['all', 'all_synthetic', 'dilithium_synthetic']:
        result = downloader.create_dilithium_synthetic_dataset()
        if result:
            downloaded.append(('Dilithium Synthetic', result))
    
    print("\n" + "=" * 70)
    print("  下载Completed")
    print("=" * 70)
    
    if downloaded:
        print("\n已下载的Data集:")
        for name, path in downloaded:
            print(f"  [OK] {name}")
            print(f"    {path}")
        
        print("\nUsage:")
        print("  python analyze_firmware_traces.py <npz_file> --algorithm aes --attacks cpa")
        print("\ne.g.:")
        for name, path in downloaded:
            if path.suffix == '.npz':
                print(f"  python analyze_firmware_traces.py {path} --algorithm aes --attacks cpa --top-n 100")
                break
    else:
        print("\n未Success下载任何Data集")
    
    print("\nNotes:")
    print("  1. DPA ContestAndASCADData集Require较长下载时间")
    print("  2. SM4的True实公开Data集非常稀少，Provide了合成Data用于Test")
    print("  3. If下载Failed，可以手动访问以下网站:")
    print("     - DPA Contest: http://www.dpacontest.org/")
    print("     - ASCAD: https://github.com/ANSSI-FR/ASCAD")
    print("     - ChipWhisperer: https://github.com/newaetech/chipwhisperer")


if __name__ == "__main__":
    main()
